
// ===============================================================================================================
// -*- C++ -*-
//
// Enemy.hpp - Enemy base class for the AI controlled hostile agents.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#ifndef __ENEMY_HPP__
#define __ENEMY_HPP__

// Local includes
#include <Math.hpp>
#include <Vector.hpp>
#include <Matrix4x4.hpp>
#include <GameLevel.hpp>
#include <Doom 3 MD5.hpp>

///
/// Enemy -- Base class for the player enemies.
///
class Enemy {

public:

	///
	/// Enemy AI states:
	///
	enum State {

		AI_STATE_DEAD,  ///< If dead, stay still on the ground waiting for respawn.
		AI_STATE_ALIVE, ///< If alive, seek and try to kill the player.
	};

	/// Update the enemy states and AI.
	virtual void Update(GameLevel * level, float playerAngle, float elapsedTime) = 0;

	/// Set the enemy rotation angle.
	virtual void SetAngle(float ang) = 0;

	/// Get the enemy rotation angle.
	virtual float GetAngle(void) const = 0;

	/// Set the enemy world position.
	virtual void SetPosition(const Vec3 & pos) = 0;

	/// Get the enemy world position.
	virtual const Vec3 & GetPosition(void) const = 0;

	///< Set the enemy AI state flag.
	inline void SetState(State s) { aiState = s; };

	///< Get the enemy AI state flag.
	inline State GetState(void) const { return (aiState); };

	/// Get a const reference to the enemy model.
	inline const DoomMD5Model * GetModel(void) const { return (model); };

	/// Get a const reference to the enemy transform.
	inline const Matrix4x4 * GetTransform(void) const { return (&transform); };

	virtual ~Enemy(void)
	{
		// Release all references:

		if (model) model->Release();
	}

protected:

	State aiState; ///< AI state flag.
	DoomMD5Model * model; ///< The enemy mesh.
	Matrix4x4 transform;  ///< World transform of the enemy.

	Enemy(void) : aiState(Enemy::AI_STATE_ALIVE), model(0), transform() { /**/ }
};

// ===============================================================================================================

///
/// Hellknight -- Implementation of the Enemy class.
/// This is the Hellknight from Doom 3. (The mesh at least).
/// Uses a very limited state machine like AI.
///
class Hellknight : public Enemy {

public:

	/// Movement speed constant.
	static const float MOVEMENT_SPEED;

	/// Number of seconds to wait for the enemy respawn, if dead.
	static const float TIME_TILL_RESPAWN;

	/// Default constructor.
	explicit Hellknight(const Vec3 & initialPos) throw (std::runtime_error);

	// Enemy Methods:

	virtual void Update(GameLevel * level, float playerAngle, float elapsedTime);

	virtual void SetAngle(float ang);
	virtual float GetAngle(void) const;

	virtual void SetPosition(const Vec3 & pos);
	virtual const Vec3 & GetPosition(void) const;

private:

	Vec3 position;   ///< World position (x,y,z).
	float rAngle;    ///< Rotation angle.
	float speedAcc;  ///< Movement speed multiplier.
	float deadAngle; ///< This will be used when the enemy is dead, to orient its body position towards the camera.
	float respawnTime; ///< Respawn time counter.
};

#endif // __ENEMY_HPP__